Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Node / ReticulumProjects / MeshChatX.git / files / scripts / build / fetch_reticulum_manual.py

Displaying Raw • Download


scripts/build/fetch_reticulum_manual.py legacy/win7 (159b2358) Text, 8.84 KB

T8b949e#!/usr/bin/env python3
T8b949e"""Fetch the Reticulum manual at build time and stage it for bundling.

The downloaded archive is extracted into ``meshchatx/public/reticulum-docs-bundled/current``
so that the application ships with an offline copy of the manual. At runtime the
backend will serve those files for any ``/reticulum-docs/`` request that does not
have a user-uploaded version overriding it.

Usage::

python scripts/build/fetch_reticulum_manual.py [--source URL] [--dest DIR]
[--force] [--include-pdf]

By default the upstream PDF/EPUB copies of the manual are excluded from the
bundle because the in-app viewer only renders the HTML version. Pass
``--include-pdf`` (or set ``MESHCHATX_DOCS_INCLUDE_PDF=1``) to keep them.

Environment variables::

MESHCHATX_RETICULUM_DOCS_URL Override the default source URL (single value).
MESHCHATX_RETICULUM_DOCS_DEST Override the destination directory.
MESHCHATX_SKIP_DOCS_FETCH If set to ``1``/``true``, exit without fetching.
MESHCHATX_DOCS_INCLUDE_PDF If set to ``1``/``true``, include PDF/EPUB.
"""

Tff7b72from T7ee787__future__ Tff7b72import Te6edf3annotations

Tff7b72import T7ee787argparse
Tff7b72import T7ee787io
Tff7b72import T7ee787logging
Tff7b72import T7ee787os
Tff7b72import T7ee787shutil
Tff7b72import T7ee787sys
Tff7b72import T7ee787urllibT7ee787.T7ee787error
Tff7b72import T7ee787urllibT7ee787.T7ee787request
Tff7b72import T7ee787zipfile
Tff7b72from T7ee787pathlib Tff7b72import Te6edf3Path

Te6edf3DEFAULT_SOURCES Tff7b72= Tb4b4b4(
Ta5d6ff"Ta5d6ffhttps://github.com/markqvist/reticulum_website/archive/refs/heads/main.zipTa5d6ff"Tb4b4b4,
Tb4b4b4)

Te6edf3DEFAULT_DEST Tff7b72= Tb4b4b4(
Te6edf3PathTb4b4b4(Tff7b72__file__Tb4b4b4)Tff7b72.Td2a8ffresolveTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffparentTff7b72.Td2a8ffparentTff7b72.Td2a8ffparent
Tff7b72/ Ta5d6ff"Ta5d6ffmeshchatxTa5d6ff"
Tff7b72/ Ta5d6ff"Ta5d6ffpublicTa5d6ff"
Tff7b72/ Ta5d6ff"Ta5d6ffreticulum-docs-bundledTa5d6ff"
Tff7b72/ Ta5d6ff"Ta5d6ffcurrentTa5d6ff"
Tb4b4b4)

Te6edf3EXTRA_BINARY_SUFFIXES Tff7b72= Tb4b4b4(Ta5d6ff"Ta5d6ff.pdfTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.epubTa5d6ff"Tb4b4b4)
T8b949e"""File suffixes for large alternate-format manuals that are excluded from the
bundled copy by default. The HTML viewer does not use them, so dropping these
saves roughly 9 MB on disk per build artifact."""


Tff7b72def Td2a8ff_is_truthyTb4b4b4(Te6edf3valueTb4b4b4: Tffa657str Tff7b72| Tff7b72NoneTb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
Tff7b72return Te6edf3value Tff7b72is Tff7b72not Tff7b72None Tff7b72and Te6edf3valueTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4) Tff7b72in Tb4b4b4{Ta5d6ff"Ta5d6ff1Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fftrueTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffyesTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffonTa5d6ff"Tb4b4b4}


Tff7b72def Td2a8ff_downloadTb4b4b4(Te6edf3urlTb4b4b4: Tffa657strTb4b4b4, Te6edf3timeoutTb4b4b4: Tffa657floatTb4b4b4) Tff7b72-Tff7b72> Tffa657bytesTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffinfoTb4b4b4(Ta5d6ff"Ta5d6ffDownloading Reticulum manual from Tffd700%sTa5d6ff"Tb4b4b4, Te6edf3urlTb4b4b4)
Te6edf3req Tff7b72= Te6edf3urllibTff7b72.Td2a8ffrequestTff7b72.Td2a8ffRequestTb4b4b4(
Te6edf3urlTb4b4b4,
Te6edf3headersTff7b72=Tb4b4b4{Ta5d6ff"Ta5d6ffUser-AgentTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmeshchatx-build-scriptTa5d6ff"Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72with Te6edf3urllibTff7b72.Td2a8ffrequestTff7b72.Td2a8ffurlopenTb4b4b4(Te6edf3reqTb4b4b4, Te6edf3timeoutTff7b72=Te6edf3timeoutTb4b4b4) Tff7b72as Te6edf3responseTb4b4b4:
Tff7b72return Te6edf3responseTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)


Tff7b72def Td2a8ff_resolve_docs_rootTb4b4b4(Te6edf3zip_bytesTb4b4b4: Tffa657bytesTb4b4b4) Tff7b72-Tff7b72> Tffa657tupleTb4b4b4[Te6edf3zipfileTff7b72.Td2a8ffZipFileTb4b4b4, Tffa657strTb4b4b4]Tb4b4b4:
T8b949e"""Return the open zip and the path prefix that contains the docs/ tree."""
Te6edf3archive Tff7b72= Te6edf3zipfileTff7b72.Td2a8ffZipFileTb4b4b4(Te6edf3ioTff7b72.Td2a8ffBytesIOTb4b4b4(Te6edf3zip_bytesTb4b4b4)Tb4b4b4)
Te6edf3names Tff7b72= Te6edf3archiveTff7b72.Td2a8ffnamelistTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3namesTb4b4b4:
Te6edf3archiveTff7b72.Td2a8ffcloseTb4b4b4(Tb4b4b4)
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffdownloaded archive is emptyTa5d6ff"Tb4b4b4)

Te6edf3root Tff7b72= Te6edf3namesTb4b4b4[T79c0ff0Tb4b4b4]Tff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4, T79c0ff1Tb4b4b4)Tb4b4b4[T79c0ff0Tb4b4b4]
Te6edf3docs_prefix Tff7b72= Ta5d6fffTa5d6ff"Tffd700{Te6edf3rootTffd700}Ta5d6ff/docs/Ta5d6ff"
Tff7b72if Tff7b72not Tffa657anyTb4b4b4(Te6edf3nameTff7b72.Td2a8ffstartswithTb4b4b4(Te6edf3docs_prefixTb4b4b4) Tff7b72for Te6edf3name Tff7b72in Te6edf3namesTb4b4b4)Tb4b4b4:
Te6edf3archiveTff7b72.Td2a8ffcloseTb4b4b4(Tb4b4b4)
Tff7b72raise Tf85149ValueErrorTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffarchive does not contain expected docs/ folder under Tffd700{Te6edf3rootTffd700}Ta5d6ff/Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3archiveTb4b4b4, Te6edf3docs_prefix


Tff7b72def Td2a8ff_extractTb4b4b4(
Te6edf3archiveTb4b4b4: Te6edf3zipfileTff7b72.Td2a8ffZipFileTb4b4b4,
Te6edf3docs_prefixTb4b4b4: Tffa657strTb4b4b4,
Te6edf3destTb4b4b4: Te6edf3PathTb4b4b4,
Te6edf3include_pdfTb4b4b4: Tffa657bool Tff7b72= Tff7b72FalseTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657tupleTb4b4b4[Tffa657intTb4b4b4, Tffa657intTb4b4b4]Tb4b4b4:
T8b949e"""Extract docs/ tree from ``archive`` into ``dest``.

Returns ``(extracted_count, skipped_binary_count)``. When ``include_pdf`` is
false, large alternate-format manuals listed in :data:`EXTRA_BINARY_SUFFIXES`
are skipped to keep shipped artifacts small.
"""
Te6edf3extracted Tff7b72= T79c0ff0
Te6edf3skipped_binary Tff7b72= T79c0ff0
Tff7b72for Te6edf3member Tff7b72in Te6edf3archiveTff7b72.Td2a8ffinfolistTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3name Tff7b72= Te6edf3memberTff7b72.Td2a8fffilename
Tff7b72if Tff7b72not Te6edf3nameTff7b72.Td2a8ffstartswithTb4b4b4(Te6edf3docs_prefixTb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3rel Tff7b72= Te6edf3nameTb4b4b4[Tffa657lenTb4b4b4(Te6edf3docs_prefixTb4b4b4) Tb4b4b4:Tb4b4b4]
Tff7b72if Tff7b72not Te6edf3rel Tff7b72or Te6edf3relTff7b72.Td2a8ffendswithTb4b4b4(Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72if Ta5d6ff"Ta5d6ff..Ta5d6ff" Tff7b72in Te6edf3relTff7b72.Td2a8ffsplitTb4b4b4(Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72if Tff7b72not Te6edf3include_pdf Tff7b72and Te6edf3relTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffendswithTb4b4b4(Te6edf3EXTRA_BINARY_SUFFIXESTb4b4b4)Tb4b4b4:
Te6edf3skipped_binary Tff7b72+Tff7b72= T79c0ff1
Tff7b72continue
Te6edf3target Tff7b72= Te6edf3dest Tff7b72/ Te6edf3rel
Tff7b72tryTb4b4b4:
Te6edf3targetTff7b72.Td2a8ffrelative_toTb4b4b4(Te6edf3destTb4b4b4)
Tff7b72except Tf85149ValueErrorTb4b4b4:
Tff7b72continue
Te6edf3targetTff7b72.Td2a8ffparentTff7b72.Td2a8ffmkdirTb4b4b4(Te6edf3parentsTff7b72=Tff7b72TrueTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72with Te6edf3archiveTff7b72.Td2a8ffopenTb4b4b4(Te6edf3memberTb4b4b4) Tff7b72as Te6edf3srcTb4b4b4, Tffa657openTb4b4b4(Te6edf3targetTb4b4b4, Ta5d6ff"Ta5d6ffwbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fhTb4b4b4:
Te6edf3shutilTff7b72.Td2a8ffcopyfileobjTb4b4b4(Te6edf3srcTb4b4b4, Te6edf3fhTb4b4b4)
Te6edf3extracted Tff7b72+Tff7b72= T79c0ff1
Tff7b72return Te6edf3extractedTb4b4b4, Te6edf3skipped_binary


Tff7b72def Td2a8fffetch_manualTb4b4b4(
Te6edf3sourcesTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4]Tb4b4b4,
Te6edf3destTb4b4b4: Te6edf3PathTb4b4b4,
Te6edf3timeoutTb4b4b4: Tffa657float Tff7b72= T79c0ff120.0Tb4b4b4,
Te6edf3forceTb4b4b4: Tffa657bool Tff7b72= Tff7b72FalseTb4b4b4,
Te6edf3include_pdfTb4b4b4: Tffa657bool Tff7b72= Tff7b72FalseTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657intTb4b4b4:
Tff7b72if Te6edf3destTff7b72.Td2a8ffexistsTb4b4b4(Tb4b4b4) Tff7b72and Tffa657anyTb4b4b4(Te6edf3destTff7b72.Td2a8ffiterdirTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72and Tff7b72not Te6edf3forceTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffinfoTb4b4b4(
Ta5d6ff"Ta5d6ffReticulum manual already present at Tffd700%sTa5d6ff (Tffd700%dTa5d6ff entries); skipping fetch.Ta5d6ff"Tb4b4b4,
Te6edf3destTb4b4b4,
Tffa657sumTb4b4b4(T79c0ff1 Tff7b72for Te6edf3_ Tff7b72in Te6edf3destTff7b72.Td2a8ffrglobTb4b4b4(Ta5d6ff"Ta5d6ff*Ta5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72return T79c0ff0

Te6edf3last_errorTb4b4b4: Tf85149Exception Tff7b72| Tff7b72None Tff7b72= Tff7b72None
Te6edf3archiveTb4b4b4: Te6edf3zipfileTff7b72.Td2a8ffZipFile Tff7b72| Tff7b72None Tff7b72= Tff7b72None
Te6edf3docs_prefixTb4b4b4: Tffa657str Tff7b72| Tff7b72None Tff7b72= Tff7b72None
Tff7b72for Te6edf3url Tff7b72in Te6edf3sourcesTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3data Tff7b72= Te6edf3_downloadTb4b4b4(Te6edf3urlTb4b4b4, Te6edf3timeoutTb4b4b4)
Te6edf3archiveTb4b4b4, Te6edf3docs_prefix Tff7b72= Te6edf3_resolve_docs_rootTb4b4b4(Te6edf3dataTb4b4b4)
Tff7b72break
Tff7b72except Tb4b4b4(Te6edf3urllibTff7b72.Td2a8fferrorTff7b72.Td2a8ffURLErrorTb4b4b4, Tf85149OSErrorTb4b4b4, Tf85149ValueErrorTb4b4b4, Te6edf3zipfileTff7b72.Td2a8ffBadZipFileTb4b4b4) Tff7b72as Te6edf3excTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffwarningTb4b4b4(Ta5d6ff"Ta5d6ffFailed to fetch Tffd700%sTa5d6ff: Tffd700%sTa5d6ff"Tb4b4b4, Te6edf3urlTb4b4b4, Te6edf3excTb4b4b4)
Te6edf3last_error Tff7b72= Te6edf3exc
Te6edf3archive Tff7b72= Tff7b72None
Te6edf3docs_prefix Tff7b72= Tff7b72None

Tff7b72if Te6edf3archive Tff7b72is Tff7b72None Tff7b72or Te6edf3docs_prefix Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72raise Tf85149SystemExitTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffCould not download Reticulum manual from any source: Tffd700{Te6edf3last_errorTffd700}Ta5d6ff"Tb4b4b4,
Tb4b4b4)

Tff7b72tryTb4b4b4:
Tff7b72if Te6edf3destTff7b72.Td2a8ffexistsTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3shutilTff7b72.Td2a8ffrmtreeTb4b4b4(Te6edf3destTb4b4b4)
Te6edf3destTff7b72.Td2a8ffmkdirTb4b4b4(Te6edf3parentsTff7b72=Tff7b72TrueTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Te6edf3extractedTb4b4b4, Te6edf3skipped_binary Tff7b72= Te6edf3_extractTb4b4b4(
Te6edf3archiveTb4b4b4,
Te6edf3docs_prefixTb4b4b4,
Te6edf3destTb4b4b4,
Te6edf3include_pdfTff7b72=Te6edf3include_pdfTb4b4b4,
Tb4b4b4)
Tff7b72finallyTb4b4b4:
Te6edf3archiveTff7b72.Td2a8ffcloseTb4b4b4(Tb4b4b4)

Tff7b72if Te6edf3extracted Tff7b72== T79c0ff0Tb4b4b4:
Tff7b72raise Tf85149SystemExitTb4b4b4(Ta5d6ff"Ta5d6ffArchive contained no docs/ files to extractTa5d6ff"Tb4b4b4)

Tff7b72if Te6edf3skipped_binaryTb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffinfoTb4b4b4(
Ta5d6ff"Ta5d6ffSkipped Tffd700%dTa5d6ff alternate-format manual file(s) (Tffd700%sTa5d6ff); pass --include-pdf to keep them.Ta5d6ff"Tb4b4b4,
Te6edf3skipped_binaryTb4b4b4,
Ta5d6ff"Ta5d6ff, Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3EXTRA_BINARY_SUFFIXESTb4b4b4)Tb4b4b4,
Tb4b4b4)

Te6edf3loggingTff7b72.Td2a8ffinfoTb4b4b4(Ta5d6ff"Ta5d6ffExtracted Tffd700%dTa5d6ff files to Tffd700%sTa5d6ff"Tb4b4b4, Te6edf3extractedTb4b4b4, Te6edf3destTb4b4b4)
Tff7b72return Te6edf3extracted


Tff7b72def Td2a8ff_parse_argsTb4b4b4(Te6edf3argvTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4]Tb4b4b4) Tff7b72-Tff7b72> Te6edf3argparseTff7b72.Td2a8ffNamespaceTb4b4b4:
Te6edf3parser Tff7b72= Te6edf3argparseTff7b72.Td2a8ffArgumentParserTb4b4b4(Te6edf3descriptionTff7b72=Tff7b72__doc__Tb4b4b4)
Te6edf3parserTff7b72.Td2a8ffadd_argumentTb4b4b4(
Ta5d6ff"Ta5d6ff--sourceTa5d6ff"Tb4b4b4,
Te6edf3actionTff7b72=Ta5d6ff"Ta5d6ffappendTa5d6ff"Tb4b4b4,
Te6edf3defaultTff7b72=Tff7b72NoneTb4b4b4,
Te6edf3helpTff7b72=Tb4b4b4(
Ta5d6ff"Ta5d6ffURL of a Reticulum website ZIP. May be passed multiple times to provide Ta5d6ff"
Ta5d6ff"Ta5d6fffallbacks. Defaults to the canonical upstream sources.Ta5d6ff"
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3parserTff7b72.Td2a8ffadd_argumentTb4b4b4(
Ta5d6ff"Ta5d6ff--destTa5d6ff"Tb4b4b4,
Tffa657typeTff7b72=Te6edf3PathTb4b4b4,
Te6edf3defaultTff7b72=Tff7b72NoneTb4b4b4,
Te6edf3helpTff7b72=Ta5d6ff"Ta5d6ffOutput directory for the extracted manual.Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3parserTff7b72.Td2a8ffadd_argumentTb4b4b4(
Ta5d6ff"Ta5d6ff--timeoutTa5d6ff"Tb4b4b4,
Tffa657typeTff7b72=Tffa657floatTb4b4b4,
Te6edf3defaultTff7b72=T79c0ff120.0Tb4b4b4,
Te6edf3helpTff7b72=Ta5d6ff"Ta5d6ffHTTP timeout in seconds.Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3parserTff7b72.Td2a8ffadd_argumentTb4b4b4(
Ta5d6ff"Ta5d6ff--forceTa5d6ff"Tb4b4b4,
Te6edf3actionTff7b72=Ta5d6ff"Ta5d6ffstore_trueTa5d6ff"Tb4b4b4,
Te6edf3helpTff7b72=Ta5d6ff"Ta5d6ffRe-fetch even if the destination already exists.Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3parserTff7b72.Td2a8ffadd_argumentTb4b4b4(
Ta5d6ff"Ta5d6ff--include-pdfTa5d6ff"Tb4b4b4,
Te6edf3actionTff7b72=Ta5d6ff"Ta5d6ffstore_trueTa5d6ff"Tb4b4b4,
Te6edf3defaultTff7b72=Te6edf3_is_truthyTb4b4b4(Te6edf3osTff7b72.Td2a8ffenvironTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffMESHCHATX_DOCS_INCLUDE_PDFTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3helpTff7b72=Tb4b4b4(
Ta5d6ff"Ta5d6ffInclude the upstream PDF/EPUB manuals in the bundle. They are Ta5d6ff"
Ta5d6ff"Ta5d6ffskipped by default to keep build artifacts smaller because the Ta5d6ff"
Ta5d6ff"Ta5d6ffin-app viewer only uses the HTML version.Ta5d6ff"
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3parserTff7b72.Td2a8ffadd_argumentTb4b4b4(
Ta5d6ff"Ta5d6ff--quietTa5d6ff"Tb4b4b4,
Te6edf3actionTff7b72=Ta5d6ff"Ta5d6ffstore_trueTa5d6ff"Tb4b4b4,
Te6edf3helpTff7b72=Ta5d6ff"Ta5d6ffReduce log output.Ta5d6ff"Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3parserTff7b72.Td2a8ffparse_argsTb4b4b4(Te6edf3argvTb4b4b4)


Tff7b72def Td2a8ffmainTb4b4b4(Te6edf3argvTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72| Tff7b72None Tff7b72= Tff7b72NoneTb4b4b4) Tff7b72-Tff7b72> Tffa657intTb4b4b4:
Te6edf3args Tff7b72= Te6edf3_parse_argsTb4b4b4(Te6edf3argv Tff7b72if Te6edf3argv Tff7b72is Tff7b72not Tff7b72None Tff7b72else Te6edf3sysTff7b72.Td2a8ffargvTb4b4b4[T79c0ff1Tb4b4b4:Tb4b4b4]Tb4b4b4)
Te6edf3loggingTff7b72.Td2a8ffbasicConfigTb4b4b4(
Te6edf3levelTff7b72=Te6edf3loggingTff7b72.Td2a8ffWARNING Tff7b72if Te6edf3argsTff7b72.Td2a8ffquiet Tff7b72else Te6edf3loggingTff7b72.Td2a8ffINFOTb4b4b4,
Tffa657formatTff7b72=Ta5d6ff"Tffd700%(message)sTa5d6ff"Tb4b4b4,
Tb4b4b4)

Tff7b72if Te6edf3_is_truthyTb4b4b4(Te6edf3osTff7b72.Td2a8ffenvironTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffMESHCHATX_SKIP_DOCS_FETCHTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffinfoTb4b4b4(
Ta5d6ff"Ta5d6ffMESHCHATX_SKIP_DOCS_FETCH is set; skipping Reticulum manual fetch.Ta5d6ff"
Tb4b4b4)
Tff7b72return T79c0ff0

Te6edf3sourcesTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72if Te6edf3argsTff7b72.Td2a8ffsourceTb4b4b4:
Te6edf3sourcesTff7b72.Td2a8ffextendTb4b4b4(Te6edf3argsTff7b72.Td2a8ffsourceTb4b4b4)
Te6edf3env_url Tff7b72= Te6edf3osTff7b72.Td2a8ffenvironTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffMESHCHATX_RETICULUM_DOCS_URLTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3env_urlTb4b4b4:
Te6edf3sourcesTff7b72.Td2a8ffappendTb4b4b4(Te6edf3env_urlTb4b4b4)
Tff7b72if Tff7b72not Te6edf3sourcesTb4b4b4:
Te6edf3sources Tff7b72= Tffa657listTb4b4b4(Te6edf3DEFAULT_SOURCESTb4b4b4)

Te6edf3env_dest Tff7b72= Te6edf3osTff7b72.Td2a8ffenvironTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffMESHCHATX_RETICULUM_DOCS_DESTTa5d6ff"Tb4b4b4)
Te6edf3dest Tff7b72= Te6edf3argsTff7b72.Td2a8ffdest Tff7b72or Tb4b4b4(Te6edf3PathTb4b4b4(Te6edf3env_destTb4b4b4) Tff7b72if Te6edf3env_dest Tff7b72else Te6edf3DEFAULT_DESTTb4b4b4)

Tff7b72if Te6edf3_is_truthyTb4b4b4(Te6edf3osTff7b72.Td2a8ffenvironTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffMESHCHATX_OFFLINE_BUILDTa5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3destTff7b72.Td2a8ffexistsTb4b4b4(Tb4b4b4) Tff7b72and Tffa657anyTb4b4b4(Te6edf3destTff7b72.Td2a8ffiterdirTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4:
Te6edf3loggingTff7b72.Td2a8ffinfoTb4b4b4(
Ta5d6ff"Ta5d6ffMESHCHATX_OFFLINE_BUILD=1 and Reticulum manual already present at Tffd700%sTa5d6ff; skipping fetch.Ta5d6ff"Tb4b4b4,
Te6edf3destTb4b4b4,
Tb4b4b4)
Tff7b72return T79c0ff0
Te6edf3loggingTff7b72.Td2a8fferrorTb4b4b4(
Ta5d6ff"Ta5d6ffMESHCHATX_OFFLINE_BUILD=1 but Reticulum manual is missing at Tffd700%sTa5d6ff"Tb4b4b4, Te6edf3dest
Tb4b4b4)
Tff7b72return T79c0ff1

Te6edf3fetch_manualTb4b4b4(
Te6edf3sourcesTff7b72=Te6edf3sourcesTb4b4b4,
Te6edf3destTff7b72=Te6edf3destTff7b72.Td2a8ffresolveTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3timeoutTff7b72=Te6edf3argsTff7b72.Td2a8fftimeoutTb4b4b4,
Te6edf3forceTff7b72=Te6edf3argsTff7b72.Td2a8ffforceTb4b4b4,
Te6edf3include_pdfTff7b72=Te6edf3argsTff7b72.Td2a8ffinclude_pdfTb4b4b4,
Tb4b4b4)
Tff7b72return T79c0ff0


Tff7b72if Tff7b72__name__ Tff7b72== Ta5d6ff"Ta5d6ff__main__Ta5d6ff"Tb4b4b4:
Tff7b72raise Tf85149SystemExitTb4b4b4(Te6edf3mainTb4b4b4(Tb4b4b4)Tb4b4b4)


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────